/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package bean.session;

import entity.ContactEntity;
import entity.DataObjectEntity;
import entity.DepartmentEntity;
import entity.InternalMessageEntity;
import entity.RightEntity;
import entity.SalesInquiryEntity;
import entity.SystemUserEntity;
import java.util.ArrayList;
import java.util.List;

import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Root;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.Metamodel;
import org.primefaces.model.DualListModel;

/**
 *
 * @author wei
 */
public abstract class AbstractFacade<T> {

    private Class<T> entityClass;

    public AbstractFacade(Class<T> entityClass) {
        this.entityClass = entityClass;
    }

    protected abstract EntityManager getEntityManager();

    public void create(T entity) {
        getEntityManager().persist(entity);
    }

    public void edit(T entity) {
        getEntityManager().merge(entity);
    }

    public void originalRemove(T entity) {
        getEntityManager().remove(getEntityManager().merge(entity));
    }
    //logical delete only: mark as archived

    public void remove(T entity) {
        if (entity instanceof DataObjectEntity) {
            DataObjectEntity dataObject = (DataObjectEntity) entity;
            dataObject.setArchived(true);
            getEntityManager().merge(dataObject);
        } else {
            getEntityManager().remove(getEntityManager().merge(entity));
        }
    }

    public T find(Object id) {
        return getEntityManager().find(entityClass, id);
    }

    public List<T> findAll() {
        CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();
        javax.persistence.criteria.CriteriaQuery cq = builder.createQuery();
        Root<DataObjectEntity> dataObjectRoot = cq.from(entityClass);
        cq.select(dataObjectRoot);
        cq.where(builder.equal(dataObjectRoot.get("archived"), false));
        return getEntityManager().createQuery(cq).getResultList();
    }

    public List<T> findAllIncludeArchived() {
        javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
        cq.select(cq.from(entityClass));
        return getEntityManager().createQuery(cq).getResultList();
    }

    //Find only non-archived items
    public List<T> findRange(int[] range) {
//        javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
//        cq.select(cq.from(entityClass));
        CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();
        javax.persistence.criteria.CriteriaQuery cq = builder.createQuery();
        Root<DataObjectEntity> dataObjectRoot = cq.from(entityClass);
        cq.select(dataObjectRoot);
        cq.where(builder.equal(dataObjectRoot.get("archived"), false));
//        javax.persistence.Query q = getEntityManager().createQuery(cq);
        javax.persistence.Query q = getEntityManager().createQuery(cq);
        q.setMaxResults(range[1] - range[0]);
        q.setFirstResult(range[0]);
        return q.getResultList();
    }

    public List<T> findRange1(int[] range) {
        javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
        cq.select(cq.from(entityClass));

        javax.persistence.Query q = getEntityManager().createQuery(cq);

        q.setMaxResults(range[1] - range[0]);
        q.setFirstResult(range[0]);
        return q.getResultList();
    }

    public int count() {
        javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
        javax.persistence.criteria.Root<T> rt = cq.from(entityClass);
        cq.select(getEntityManager().getCriteriaBuilder().count(rt));
        javax.persistence.Query q = getEntityManager().createQuery(cq);
        return ((Long) q.getSingleResult()).intValue();
    }

    public DepartmentEntity getDepartmentByName(String name) {

        CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();
        javax.persistence.criteria.CriteriaQuery cq = builder.createQuery();
        Root<DepartmentEntity> dataObjectRoot = cq.from(DepartmentEntity.class);
        cq.select(dataObjectRoot);
        cq.where(builder.equal(dataObjectRoot.get("name"), name));
        return (DepartmentEntity) getEntityManager().createQuery(cq).getSingleResult();
    }

    public List<RightEntity> findRange2(int[] range, String name) {
        CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();
        javax.persistence.criteria.CriteriaQuery cq = builder.createQuery();
        cq.select(cq.from(entityClass));
        Root<RightEntity> dataObjectRoot = cq.from(RightEntity.class);
        cq.where(builder.equal(dataObjectRoot.get("name"), name));
        javax.persistence.Query q = getEntityManager().createQuery(cq);
        q.setMaxResults(range[1] - range[0]);
        q.setFirstResult(range[0]);
        return q.getResultList();
    }

    public List<InternalMessageEntity> searchUser(String keyword) {
        Query query = getEntityManager().createQuery("SELECT u FROM SystemUser u"
                + " WHERE u.firstName like %" + keyword
                + "% OR u.lastName like %" + keyword + "%"
                + "% OR u.name like %" + keyword + "%;");
        return query.getResultList();
    }

    public DataModel searchSalesInquiryByCreatedBy(String input) {
        CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();
        javax.persistence.criteria.CriteriaQuery<SalesInquiryEntity> cq = builder.createQuery(SalesInquiryEntity.class);
        Metamodel m = getEntityManager().getMetamodel();
        EntityType<SalesInquiryEntity> salesInquiryType = m.entity(SalesInquiryEntity.class);
        Root<SalesInquiryEntity> salesInquiryRoot = cq.from(SalesInquiryEntity.class);
        cq.select(salesInquiryRoot);
        cq.where(builder.like(salesInquiryRoot.get(salesInquiryType.getDeclaredSingularAttribute("firstName", String.class)), "%" + input + "%"));
        return new ListDataModel(getEntityManager().createQuery(cq).getResultList());
    }

    public void flush() {
        getEntityManager().flush();
    }

    public ArrayList<ContactEntity> getAllContact() {
        Query query = getEntityManager().createQuery("SELECT c FROM Contact c WHERE c.email is NOT NULL");

        ArrayList contact = new ArrayList<ContactEntity>();
        for (Object o : query.getResultList()) {
            ContactEntity p = (ContactEntity) o;
            contact.add(p);
        }
        return contact;
    }

//    public DualListModel<ContactEntity> getAllEmailAdd() {
//
//        List<ContactEntity> source = new ArrayList<ContactEntity>();
//        List<ContactEntity> target = new ArrayList<ContactEntity>();
//        ArrayList<ContactEntity> contact = getAllContact();
//        for (int i = 0; i < contact.size(); i++) {
//            source.add(contact.get(i));
//        }
//        DualListModel addressBook = new DualListModel<ContactEntity>(source, target);
//        return addressBook;
//    }
    
}
